package com.dhl;

import com.dhl.annotation.*;
import com.dhl.aware.BeanNameAware;
import com.dhl.config.BeanDefinition;
import com.dhl.constant.Constant;
import com.dhl.init.BeanPostProcessor;
import com.dhl.init.InitializingBean;
import com.dhl.utils.FileUtils;

import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.*;

/**
 * @author danghailiang
 * @date 2023年01月16日 9:58
 */
public class SpringApplicationContent {
    /**
     * 定义的bean
     */
    private static Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
    private static Map<String, Object> singletonMap = new HashMap<>();

    private static List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();

    private Class configClass;

    public SpringApplicationContent(Class obj) {
        configClass = obj;
        // 扫描
        scan();
        // 创建bean
        for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : beanDefinitionMap.entrySet()) {
            String beanName = beanDefinitionEntry.getKey();
            BeanDefinition beanDefinition = beanDefinitionEntry.getValue();
            // 单例bean创建
            if (beanDefinition.getScope().equals(Constant.SCOPE_SINGLETON)) {
                // 创建Bean
                Object bean = doCreate(beanName, beanDefinition);
                singletonMap.put(beanName, bean);
            }
        }
    }

    /**
     * 创建bean
     *
     * @param beanName
     * @param beanDefinition
     * @return
     */
    private Object doCreate(String beanName, BeanDefinition beanDefinition) {
        Class clazz = beanDefinition.getClazz();

        Object instance = null;
        try {
            instance = clazz.getConstructor().newInstance();
            // 获取所有的属性 Autowired DI
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                if (field.isAnnotationPresent(Autowired.class)) {
                    field.setAccessible(true);
                    field.set(instance, getBean(field.getName()));
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        // 主要实现aop功能 初始化之后
        for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
            instance = beanPostProcessor.postProcessBeforeInitialization(instance,beanName);
        }
        // 初始化
        if(instance instanceof InitializingBean){
            ((InitializingBean) instance).afterPropertiesSet();
        }
        // 主要实现aop功能 初始化之后
        for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
            instance = beanPostProcessor.postProcessAfterInitialization(instance,beanName);
        }


        // 创建之前
//        Method[] methods = clazz.getMethods();
//        for (Method method : methods) {
//            if (method.isAnnotationPresent(PostConstruct.class)) {
//                try {
//                    method.invoke(instance);
//                } catch (Exception e) {
//                    throw new RuntimeException(e);
//                }
//            }
//        }

        // 创建中


        // 创建之后

        return instance;
    }

    public void scan() {
        if (Objects.nonNull(configClass)) {
            ComponentScan componentScan = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            if (componentScan != null) {
                // 获取包扫描路径 com.dhl
                String packagePath = componentScan.value();
                // com/dhl
                String targetPath = packagePath.replace(".", "/");
                ClassLoader classLoader = configClass.getClassLoader();
                URL resource = classLoader.getResource(targetPath);
                if (Objects.nonNull(resource)) {
                    File fileDirectory = new File(resource.getFile());
                    // 获取所有的文件
                    List<File> files = new ArrayList<>();
                    FileUtils.files(files, fileDirectory);
                    for (File file : files) {
//                        \com\dhl\Application.class
                        String absolutePath = file.getAbsolutePath();
                        String path = packagePath.replace(".", "\\");
                        // 对路径进行处理
                        absolutePath = absolutePath.substring(absolutePath.lastIndexOf(path), absolutePath.length() - 6).replace("\\", ".");
                        // 根据文件名进行反射
                        try {
                            Class<?> clazz = classLoader.loadClass(absolutePath);
                            // 判断是否依赖注入
                            if (clazz.isAnnotationPresent(Component.class)) {

                                // 实现BeanPostProcessor
                                if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
                                    BeanPostProcessor beanPostProcessor = (BeanPostProcessor) clazz.getConstructor().newInstance();
                                    beanPostProcessors.add(beanPostProcessor);
                                }

                                BeanDefinition beanDefinition = new BeanDefinition();
                                beanDefinition.setClazz(clazz);
                                String beanName = clazz.getAnnotation(Component.class).value();

                                if ("".equals(beanName)) {
                                    beanName = Introspector.decapitalize(clazz.getSimpleName());
                                }
                                // 判断是否是多例
                                if (clazz.isAnnotationPresent(Scope.class)) {
                                    // 多例
                                    String scope = clazz.getAnnotation(Scope.class).value();
                                    if (!"".equals(scope) && scope.equals(Constant.SCOPE_PROTOTYPE)) {
                                        // 多列
                                        beanDefinition.setScope(Constant.SCOPE_PROTOTYPE);
                                    } else {
                                        // 单例
                                        beanDefinition.setScope(Constant.SCOPE_SINGLETON);
                                    }
                                } else {
                                    // 单例
                                    beanDefinition.setScope(Constant.SCOPE_SINGLETON);
                                }
                                // 保存
                                beanDefinitionMap.put(beanName, beanDefinition);
                            }
                        } catch (ClassNotFoundException e) {
                            throw new RuntimeException(e);
                        } catch (InvocationTargetException e) {
                            throw new RuntimeException(e);
                        } catch (InstantiationException e) {
                            throw new RuntimeException(e);
                        } catch (IllegalAccessException e) {
                            throw new RuntimeException(e);
                        } catch (NoSuchMethodException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            }
        }

    }

    public Object getBean(String name) {
        // 判断是否存在
        if (!beanDefinitionMap.containsKey(name)) {
            throw new RuntimeException("获取的bean不存在");
        }
        Object bean = null;
        BeanDefinition beanDefinition = beanDefinitionMap.get(name);
        if (beanDefinition.getScope().equals(Constant.SCOPE_SINGLETON)) {
            bean = singletonMap.get(name);
            if (Objects.isNull(bean)) {
                bean = doCreate(name, beanDefinition);
                singletonMap.put(name, bean);
            }
        } else {
            bean = doCreate(name, beanDefinition);
        }
        return bean;
    }

}
